/** \file    bitmap.h
  * \brief   Binary raster
  * \date    2001 - 2003
  * \author  Pavel Agapov
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/bitmap.h,v 1.6 2005/05/12 18:22:19 cscom1r4 Exp $
  */

#if !defined(IMGLIB_BITMAP_H)
#define IMGLIB_BITMAP_H

#include "imglib/raster.h"

namespace img {

class bitmap {
protected:
	class bit;
	class const_bit;
	friend class bit;
	friend class const_bit;
public:
	typedef bool elem_type;
	typedef float real_elem_type;
	typedef raster_iterator<bitmap, bit> iterator;
	typedef const_raster_iterator<bitmap, const_bit, iterator> const_iterator;
private:
	typedef unsigned char byte;
	byte *				_data;
	bool				_owner;
	size_type			_width;
	size_type			_height;
	size_type			_alignment;
	order_type			_order;
	size_type			_scansize;
	size_type			_bytes;
	std::vector<byte *>	_scans;
private:
	bool get_bit(size_type x, size_type y) const {
		const byte & b = _scans[y][x / 8];
		byte mask = static_cast<byte>(128 >> (x % 8));
		return (b & mask) != 0;
	}
	void set_bit(size_type x, size_type y, bool value) {
		byte & b = _scans[y][x / 8];
		byte mask = static_cast<byte>(128 >> (x % 8));
		if (value)
			b |= mask;
		else
			b &= ~mask;
	}
protected:
	class bit {
		bitmap &	_bmp;
		size_type	_x, _y; 
	public:
		bit(bitmap & b, size_type x, size_type y)
			: _bmp(b), _x(x), _y(y) { }
		operator bool() const 
			{ return _bmp.get_bit(_x, _y); }
		bool operator = (bool value) 
			{ _bmp.set_bit(_x, _y, value); return value; }
	};
	class const_bit {
		const bitmap &	_bmp;
		size_type		_x, _y;
	public:
		const_bit(const bitmap & b, size_type x, size_type y)
			: _bmp(b), _x(x), _y(y) { }
		operator bool() const 
			{ return _bmp.get_bit(_x, _y); }
	};
private:
	void update_scans();
	void recalc(size_type w, size_type h, size_type a);
public:
	bitmap(size_type w = 0, size_type h = 0, size_type a = 4)
		: _data(0), _owner(true), _width(0), _height(0), _alignment(1), _order(top_down), _scansize(0), _bytes(0)
		{ resize(w, h, a); }
	bitmap(size_extent e, size_type a = 4)
		: _data(0), _owner(true), _width(0), _height(0), _alignment(1), _order(top_down), _scansize(0), _bytes(0)
		{ resize(e.sx, e.sy, a); }
	bitmap(void * data, size_type w = 0, size_type h = 0, size_type a = 4)
		: _data(0), _owner(true), _width(0), _height(0), _alignment(1), _order(top_down), _scansize(0), _bytes(0)
		{ attach(data, w, h, a); }
	bitmap(void * data, size_extent e, size_type a = 4)
		: _data(0), _owner(true), _width(0), _height(0), _alignment(1), _order(top_down), _scansize(0), _bytes(0)
		{ attach(data, e.sx, e.sy, a); }
	bitmap (const bitmap & rhs) 
		: _data(0), _owner(true), _width(0), _height(0), _alignment(1), _order(top_down), _scansize(0), _bytes(0)
		{ operator =(rhs); }
	~bitmap()
		{ clear(); }
	bool owner() const
		{ return _owner; }
	size_type bytes() const
		{ return _bytes; }
	size_type scansize() const
		{ return _scansize; }
	size_type width() const
		{ return _width; }
	size_type height() const
		{ return _height; }
	size_extent dim() const
		{ return size_extent(_width, _height); }
	size_type size() const
		{ return _width * _height; }
	size_type alignment() const
		{ return _alignment; }
	order_type order() const
		{ return _order; }
	const void * data() const
		{ return _data; }
	void * data()
		{ return _data; }
	bool empty() const
		{ return _data == 0; }
	void * scan(size_type y)
		{ return _scans[y]; }
	const void * scan(size_type y) const
		{ return _scans[y]; }
	const_bit at(size_type x, size_type y) const
		{ return const_bit(* this, x, y); }
	const_bit operator () (size_type x, size_type y) const
		{ return const_bit(* this, x, y); }
	const_bit operator [] (point<size_type> p) const
		{ return const_bit(* this, p.x, p.y); }
	bit at(size_type x, size_type y)
		{ return bit(* this, x, y); }
	bit operator () (size_type x, size_type y)
		{ return bit(* this, x, y); }
	bit operator [] (point<size_type> p)
		{ return bit(* this, p.x, p.y); }
	const_iterator begin() const
		{ return const_iterator(* this, 0, 0); }
	const_iterator end() const
		{ return const_iterator(* this, 0, _height); }
	iterator begin()
		{ return iterator(* this, 0, 0); }
	iterator end()
		{ return iterator(* this, 0, _height); }
public:
	template <class R> bitmap & operator = (const R & raster) {
		resize(raster.width(), raster.height());
		std::copy(raster.begin(), raster.end(), begin());
		return * this;
	}
	bitmap & operator = (const bitmap & rhs) {
		if (&rhs == this)
			return * this;
		resize(rhs.width(), rhs.height());
		if (scansize() == rhs.scansize() && order() == rhs.order())
			memcpy(data(), rhs.data(), bytes());
		else
			for (unsigned int n = 0; n < _scans.size(); ++n)
				memcpy(_scans[n], rhs._scans[n], _width / 8 + ((_width % 8) != 0 ? 1 : 0));
		return * this;                                                                                
	}
	void resize(size_type w, size_type h, size_type a = 4);
	void resize(size_extent e, size_type a = 4) 
		{ resize(e.sx, e.sy, a); }
	void clear() {
		if (_owner)
			resize(0, 0);
		else
			detach();
	}
	void attach(void * data, size_type w, size_type h, size_type a = 4);
	void attach(void * data, size_extent e, size_type a = 4) 
		{ attach(data, e.sx, e.sy, a); }
	void attach(const bitmap & master) 
		{ attach(master._data, master._width, master._height, master._alignment); 
		  order(master._order); }
	void take(void * data, size_type w, size_type h, size_type a = 4) {
		attach(data, w, h, a);
		_owner = true;
	}
	void take(void * data, size_extent e, size_type a = 4) 
		{ take(data, e.sx, e.sy, a); }
	void * detach();
	void alignment(size_type a) {
		if (_owner)
			resize(_width, _height, a);
		else
			attach(_data, _width, _height, a);
	}
	void order(order_type o) {
		if (o != _order) {
			_order = o;
			update_scans();
		}
	}
	void flip_order() {
		_order = img::flip(_order);
		update_scans();
	}
	void flip();
	void fill(bool value);
	template <class R>
	void copy_attributes(const R & r) {
		resize(r.width(), r.height(), r.alignment());
		order(r.order());
	}
	void swap(bitmap &b);
	int  set_bit_count() const;
	void inverse();
	template <class OP>	
		friend void combine(bitmap & bmp, const bitmap & src, OP & op);	
	template <class OP> 
		friend void combine(bitmap & bmp, int xd, int yd, int wd, int hd, const bitmap & src, int xs, int ys, OP & op);
	template <class R, class PR> 
		friend void mask(bitmap & bmp, int xd, int yd, int wd, int hd, const R & raster, int xs, int ys, PR & pr);
};

} //namespace img

namespace std {

template <class T> 
void swap(T&, T&);

template <> 
inline void swap(img::bitmap & lhs, img::bitmap & rhs) {
	lhs.swap(rhs);
}

} //namespace std

#include "imglib/bmpcomb.h"

#endif // IMGLIB_BITMAP_H
